﻿module StateMonad


type State<'a,'s> = 's -> 'a * 's

type StateMonad() =   
  member m.Return a = (fun s -> a, s)   
  member m.Bind(x, f) = (fun s -> let a, s_ = x s in f a s_)  
  member this.Zero() = this.Return()
  member this.Combine(p1,p2) =
    this.Bind(p1, fun _ -> p2)
  member this.For(items:seq<'a>, body:'a -> State<Unit,'s>)  : State<Unit,'s> =
    fun s ->
      if items |> Seq.length = 0 then 
        this.Return() s
      else
        let hd,tl = items |> Seq.head, items |> Seq.skip 1
        this.Combine(body hd, this.For(tl, body)) s
  member this.ReturnFrom(s) = s
  member this.Delay s = s()
  member this.Run s = s

(*
State monad builder.
*)
let state = new StateMonad() 

(*
Monadic state getter.
*)
let getState = (fun s -> s, s) 

(*
Monadic state setter.
*)
let setState s = (fun _ -> (), s)  

(*
Monadic state run function.
*)
let execute m s = m s 

//let rec mapM pred (xs : 'a list) =
//  fun s ->
//    match xs with
//    | [] -> 
//      [], s
//    | x :: xs -> 
//      let new_val, s' = pred x s
//      let tail, s'' = (mapM pred xs) s'
//      (x::tail), s''   